/*******************************************************************************
FittingDataPanel.java
Copyright (C) Victor Olaya

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*******************************************************************************/
package es.unex.meigas.extFillData;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerListModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;

import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYDotRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import es.unex.meigas.core.DasocraticElement;
import es.unex.meigas.core.Tree;
import es.unex.sextante.libMath.regression.LeastSquaresFit;
import info.clearthought.layout.TableLayout;

public class FittingDataPanel extends JDialog{

	private static final int HEIGHT_MARGIN = 65;
	private static final int WIDTH_MARGIN = 40;
	private static final int WIDTH = 500;
	private static final int HEIGHT = 350;
	private JFreeChart chart;
	private ChartPanel jPanelChart = null;
	private LeastSquaresFit m_Lsf;
	private int width = WIDTH, height = HEIGHT;
	private JLabel jLabel;
	private JSpinner jSpinnerOrder;
	private JLabel jLabelOrder;
	private JPanel jPanelOrder;
	private JButton jButtonCancel;
	private JButton jButtonOk;
	private JPanel jPanelButtons;
	private ArrayList m_Trees;
	private XYVariables m_XY;

	private XYSeriesCollection m_Data1 = new XYSeriesCollection();
	private XYSeriesCollection m_Data2 = new XYSeriesCollection();

	private String m_sParameters[] = {"Diametro normal", "Altura total", "Altura de fuste",
									  "Volumen sin corteza", "Volumen con corteza",
									  "Espesor de corteza", "Diametro de copa"};

	public FittingDataPanel(LeastSquaresFit lsf, ArrayList trees, XYVariables xy) {

		m_Lsf = lsf;
		m_Trees = trees;
		m_XY = xy;

	    createChart();

		initialize();

		Plot plot = this.jPanelChart.getChart().getPlot();
		plot.setOutlineStroke(new BasicStroke(1));
		plot.setOutlinePaint(Color.blue);

	}

	private void initialize() {

		TableLayout flowLayout = new TableLayout(new double[][] {
				{ TableLayout.FILL, TableLayout.FILL, TableLayout.FILL,
					TableLayout.FILL },
					{ 25.0, TableLayout.FILL, TableLayout.FILL, 40.0 } });
		flowLayout.setHGap(5);
		flowLayout.setVGap(5);
		this.setLayout(flowLayout);
		this.setSize(new java.awt.Dimension(width, height));
		this.setPreferredSize(new java.awt.Dimension(width, height));
		String s = m_Lsf.getExpression();
		this.add(getJLabel(), "0, 0, 3, 0");
		getJLabel().setText("Ecuacion de ajuste: y = " + s);
		this.add(getChart(), "0, 1, 3, 2");
		this.add(getJPanelButtons(), "2, 3, 3, 3");
		this.add(getJPanelOrder(), "0, 3, 1, 3");

	}

	public ChartPanel getChart(){

		if(jPanelChart == null){
			jPanelChart = new ChartPanel(chart);
			jPanelChart.setSize(new java.awt.Dimension(width - WIDTH_MARGIN, height - HEIGHT_MARGIN));
			jPanelChart.setPreferredSize(new java.awt.Dimension(width - WIDTH_MARGIN, height - HEIGHT_MARGIN));
			jPanelChart.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.Color.gray,1));
		}
		return 	jPanelChart;
	}

	private void createChart() {

        updateDataset();

    	chart = ChartFactory.createScatterPlot(null,
    											m_sParameters[m_XY.x],
    											m_sParameters[m_XY.y],
    											m_Data1,
		    									PlotOrientation.VERTICAL,
		    									false, true, true);

    	XYPlot plot = chart.getXYPlot();
    	plot.setRenderer(new XYDotRenderer());
    	plot.setDomainCrosshairVisible(true);
    	plot.setRangeCrosshairVisible(true);
    	plot.getRenderer().setSeriesPaint(0, Color.blue);


    	XYItemRenderer renderer = new StandardXYItemRenderer();
        renderer.setSeriesPaint(0, Color.red);

        plot.setDataset(1, m_Data2);
        plot.setRenderer(1, renderer);

    }



	private void updateDataset() {

		setOriginalDataset();
    	setDatasetFromFitting();

	}

	public void setComponentSize(int w, int h){

		width = w;
		height = h;
		this.setSize(new java.awt.Dimension(w, h));
		this.setPreferredSize(new java.awt.Dimension(w, h));
		jPanelChart.setSize(new java.awt.Dimension(w - WIDTH_MARGIN, h - HEIGHT_MARGIN));
		jPanelChart.setPreferredSize(new java.awt.Dimension(w - WIDTH_MARGIN, h - HEIGHT_MARGIN));

	}

	private void setOriginalDataset(){

    	int i;
    	XYSeries series = new XYSeries("");

		double x[] = new double[m_Lsf.getNumPoints()];
		double y[] = new double[m_Lsf.getNumPoints()];
		m_Lsf.getPoints(x, y);
		for (i = 0; i < x.length; i++){
			series.add(x[i], y[i]);
		}

		m_Data1.removeAllSeries();
		m_Data1.addSeries(series);

	}

	private void setDatasetFromFitting(){

		int i;
		final int STEPS = 200;
		double x,y;
		XYSeries series = new XYSeries("");

		double dStep = ( m_Lsf.getXMax() - m_Lsf.getXMin() ) / STEPS;

		for (i = 0; i < STEPS; i++){
			x = m_Lsf.getXMin() + dStep * i;
			y = m_Lsf.getY(x);
			series.add(x, y);
		}

		m_Data2.removeAllSeries();
		m_Data2.addSeries(series);

	}

	private JPanel getJPanelButtons() {

		if (jPanelButtons == null) {
			jPanelButtons = new JPanel();
			jPanelButtons.add(getJButtonOk());
			jPanelButtons.add(getJButtonCancel());
		}
		return jPanelButtons;

	}

	private JButton getJButtonOk() {

		if (jButtonOk == null) {
			jButtonOk = new JButton();
			jButtonOk.setText("Aceptar");
			jButtonOk.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent evt) {
					fillData();
					cancel();
				}
			});
		}
		return jButtonOk;

	}

	private JButton getJButtonCancel() {

		if (jButtonCancel == null) {
			jButtonCancel = new JButton();
			jButtonCancel.setText("Cancelar");
			jButtonCancel.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent evt) {
					cancel();
				}
			});
		}
		return jButtonCancel;

	}

	private void fillData(){

		int iTree;
		Tree tree;
		double dX, dY;

		for (iTree = 0; iTree < m_Trees.size(); iTree++){
			tree = (Tree) m_Trees.get(iTree);
			dY = getValue(m_XY.y, tree);
			if (dY == DasocraticElement.NO_DATA){
				dX = getValue(m_XY.x, tree);
				if (dX != DasocraticElement.NO_DATA){
					setValue(m_XY.y, m_Lsf.getY(dX), tree);
				}
			}
		}

	}

	private double getValue(int y, Tree tree){

		double dValue;

		switch (y){
		case FillDataPanel.DBH:
			dValue = tree.getDBH().getValue();
			break;
		case FillDataPanel.HEIGHT:
			dValue = tree.getHeight().getValue();
			break;
		case FillDataPanel.LOG_HEIGHT:
			dValue = tree.getLogHeight().getValue();
			break;
		case FillDataPanel.VOLUME_WITH_BARK:
			dValue = tree.getVolumeWithBark().getValue();
			break;
		case FillDataPanel.VOLUME_WITHOUT_BARK:
			dValue = tree.getVolumeWithoutBark().getValue();
			break;
		case FillDataPanel.BARK:
			dValue = tree.getBark().getValue();
			break;
		case FillDataPanel.CROWN_DIAMETER:
			dValue = tree.getCrownDiameter().getValue();
			break;
		default:
			return DasocraticElement.NO_DATA;
		}

		return dValue;

	}

	private void setValue(int y, double dValue, Tree tree) {

		switch (y){
		case FillDataPanel.DBH:
			tree.getDBH().setValue(dValue);
			tree.getDBH().setIsEstimated(true);
			break;
		case FillDataPanel.HEIGHT:
			tree.getHeight().setValue(dValue);
			tree.getHeight().setIsEstimated(true);
			break;
		case FillDataPanel.LOG_HEIGHT:
			tree.getLogHeight().setValue(dValue);
			tree.getLogHeight().setIsEstimated(true);
			break;
		case FillDataPanel.VOLUME_WITH_BARK:
			tree.getVolumeWithBark().setValue(dValue);
			tree.getVolumeWithBark().setIsEstimated(true);
			break;
		case FillDataPanel.VOLUME_WITHOUT_BARK:
			tree.getVolumeWithoutBark().setValue(dValue);
			tree.getVolumeWithoutBark().setIsEstimated(true);
			break;
		case FillDataPanel.BARK:
			tree.getBark().setValue(dValue);
			tree.getBark().setIsEstimated(true);
			break;
		case FillDataPanel.CROWN_DIAMETER:
			tree.getCrownDiameter().setValue(dValue);
			tree.getCrownDiameter().setIsEstimated(true);
			break;
		default:
		}

	}

	protected void cancel() {

		this.dispose();
		this.setVisible(false);

	}

	private JPanel getJPanelOrder() {

		if (jPanelOrder == null) {
			jPanelOrder = new JPanel();
			jPanelOrder.add(getJLabelOrder());
			jPanelOrder.add(getJSpinnerOrder());
		}

		return jPanelOrder;

	}

	private JLabel getJLabelOrder() {

		if (jLabelOrder == null) {
			jLabelOrder = new JLabel();
			jLabelOrder.setText("Orden del polinomio de ajuste:");
		}
		return jLabelOrder;

	}

	private JSpinner getJSpinnerOrder() {

		if (jSpinnerOrder == null) {
			SpinnerListModel jSpinnerOrderModel = new SpinnerListModel(
				new String[] { "1", "2", "3", "4", "5", "6", "7" });
			jSpinnerOrder = new JSpinner();
			jSpinnerOrder.setModel(jSpinnerOrderModel);
			jSpinnerOrder.addChangeListener(new ChangeListener() {
				public void stateChanged(ChangeEvent evt) {
					String s = (String) ((SpinnerListModel)jSpinnerOrder.getModel()).getValue();
					m_Lsf.calculate(Integer.parseInt(s));
					updateDataset();
					s = m_Lsf.getExpression();
					getJLabel().setText("Ecuacion de ajuste: y = " + s);
				}
			});
		}

		return jSpinnerOrder;

	}

	private JLabel getJLabel() {

		if (jLabel == null) {
			jLabel = new JLabel();
			jLabel.setAlignmentX(0.5f);
		}
		return jLabel;

	}

}
